/*
 * HeteroVector.hpp
 *
 *  Created on: Apr 21, 2009
 *      Author: Jae Hyuk Kwak
 */

#ifndef HETEROVECTOR_HPP_
#define HETEROVECTOR_HPP_
#include "loki/Typelist.h"
#include "loki/TypelistMacros.h"
#include <vector>
namespace TestingCoverage {
using namespace std;
using namespace Loki;
using namespace Loki::TL;


template< typename ValueTypes, unsigned int index1 >
class EachVectorHolder;

template< typename ValueTypes >
class EachVectorHolder < ValueTypes, 0 > {
public:
	typedef typename TypeAt< ValueTypes, 0 >::Result EachType;

	void setValue( vector< EachType > values) {
		values_ = values;
	}

	void push_back( EachType value ) {
		values_.push_back( value );
	}

	void replace( unsigned int pos, EachType value ) {
		values_.at(pos) = value;
	}

	EachType getValue(size_t index2) const {
		return values_.at(index2);
	}

	size_t size() const {
		return values_.size();
	}

	vector< EachType > getVector() {
		return values_;
	}
private:
	vector< EachType > values_;
};

template< typename ValueTypes, unsigned int index1 >
class EachVectorHolder : public EachVectorHolder< ValueTypes, index1 -1 > {
public:
	typedef typename TypeAt< ValueTypes, index1 >::Result EachType;

	void setValue( vector< EachType > values) {
		values_ = values;
	}

	void push_back( EachType value ) {
		values_.push_back( value );
	}

	void replace( unsigned int pos, EachType value ) {
		values_.at(pos) = value;
	}

	EachType getValue( size_t index2 ) const {
		return values_.at(index2);
	}

	size_t size() const {
		return values_.size();
	}

	vector< EachType > getVector() {
		return values_;
	}
private:
	vector< EachType > values_;
};


template < typename TList >
class HeteroVector {
private:
	enum { Length_ = Length< TList >::value };
public:
	template < unsigned int index1, size_t ArraySize >
	void set( typename TypeAt< TList, index1 >::Result (&values)[ArraySize] ) {
		typedef typename TypeAt< TList, index1 >::Result EachType;
		for(unsigned int i = 0; i < ArraySize; ++i)
			HeteroVector< TList >::template push_back< index1 >( values[i] );
	}

	template < unsigned int index1 >
	void push_back( typename TypeAt< TList, index1 >::Result value ) {
		vectorHolders_.EachVectorHolder< TList, index1 >::push_back( value );
	}

	template < unsigned int index1 >
	void replace( unsigned int pos, typename TypeAt< TList, index1 >::Result value ) {
		vectorHolders_.EachVectorHolder< TList, index1 >::replace( pos, value );
	}

	unsigned int numberOfTypes() const {
		return Length_;
	}

	template< unsigned int index1 >
	unsigned int size() const {
		return vectorHolders_.EachVectorHolder< TList, index1 >::size();
	}

	template< unsigned int index1 >
	typename TypeAt< TList, index1 >::Result get( unsigned int index2 ) const {
		return vectorHolders_.EachVectorHolder< TList, index1 >::getValue(index2);
	}

	template< unsigned int index1 >
	vector< typename TypeAt< TList, index1 >::Result > getVector() {
		return vectorHolders_.EachVectorHolder< TList, index1 >::getVector();
	}

private:
	EachVectorHolder< TList, Length_ -1 > vectorHolders_;
};

}

#endif /* HETEROVECTOR_HPP_ */
